package gbench.sandbox.tensor;

import static gbench.common.tree.LittleTree.cph2;
import static gbench.common.tree.LittleTree.series;

import java.util.function.Function;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;

import gbench.common.fs.XlsFile.DRow;
import gbench.common.fs.XlsFile.DataMatrix;
import gbench.commonApp.data.DataMatrixApp;
import static gbench.common.tree.LittleTree.IRecord.*;
import static gbench.common.tree.LittleTree.*;

/**
 * 
 * @author gbench
 *
 */
public class JunitPerceptron extends DataMatrixApp{
    
    @Test
    public void foo() {
        final var numbers = "1:3";// 数据长度
        final var dd = cph2(series,numbers,numbers,numbers).collect(dmc);
        println("rawdata:");
        final var wts = A(10d,8d,9d);
        final var bias = 10d;
        final Function<Double,Double> activation = e->e;
        final var y_hat = dd.perceptron(bias, wts, activation);
        println(dd.addColumns(y_hat));
    }
    
    @Test
    public void qux() {
        final var numbers = "1:3";// 数据长度
        final var dd = cph2(series,numbers,numbers,numbers).collect(dmc);
        println("rawdata:");
        final var wts = A(10.7d,8d,9d);
        final var bias = 10d;
        final Function<Double,Double> activation = e->e;
        
        final var y1 = dd.mmult(REC(0,wts).dblmx()).add(bias);
        final var y2 = dd.perceptron(bias, wts, activation);
        println(y1);println(y2);
        final var y = y1;
        
        final var wts_hat = A(10.9d,8.3d,9d);
        final var bias_hat = 10d;
        //final var eps= 1e10-5;
        final Function< DataMatrix<Double>, Supplier<Double> > f = rr -> () -> y.sub(rr.perceptron(bias_hat, wts_hat, activation))
            .getColumn(0).map(e->e*e).sum();
        final var delta = f.apply(dd);
        println(delta.get());
    }
    
    @Test
    public void bar() {
        final var thetas = REC(
            "layer0", REC(
                    "n0", A(1d, A(1d,1d,1d,1d,1d)),
                    "n1", A(2d, A(1d,1d,1d,1d,1d)),
                    "n2", A(3d, A(1d,1d,1d,1d,1d))
            ),"layer1", REC(
                    "n0", A(1d, A(1d,1d,1d,1d,1d)),
                    "n1", A(2d, A(1d,1d,1d,1d,1d)),
                    "n2", A(3d, A(1d,1d,1d,1d,1d))
            )
        );
        
        final Function<String,Double[]> theta= thetas::path2dbls;
        final var dd = cph2(series,RPTA(5,"1:20")).collect(dmc);
        int i =  0;
        if(i>0) {
            timeit(()->{
                final Function<String,Function<DataMatrix<Double>,DataMatrix<Double>>> perceptron = path -> dmx ->{
                    final var aa = theta.apply(path);
                    return dmx.perceptron(CAR(aa),CDR(aa),e->e);
                };
                
                @SuppressWarnings("unused")
                final var y = perceptron.apply("layer0/n1").apply(dd);
                //println(y);
                //println(dd);
            });
        }else {
            timeit(()->{
                final var tt = theta.apply("layer0/n1");
                dd.rfor(row->{
                    @SuppressWarnings("unused")
                    var w = row.stream().collect(DRow.perceptron(CAR(tt), CDR(tt), e->e));
                });
            });
        }
        
    }
    
    @Test
    public void bar2() {
        final var thetas = REC(
            "layer0", REC(
                    "n0", A(1d, A(1d,1d,1d,1d,1d)),
                    "n1", A(100d, A(1d,2d,3d,4d,5d)),
                    "n2", A(0d, A(0d,0d,0d,0d,0d))
            ),"layer1", REC(
                    "n0", A(1d, A(1d,1d,1d,1d,1d)),
                    "n1", A(2d, A(1d,1d,1d,1d,1d)),
                    "n2", A(3d, A(1d,1d,1d,1d,1d))
            )
        );
        
        final Function<String,Double[]> theta_i= thetas::path2dbls;
        final var dd = cph2(series,RPTA(5,"1:5")).collect(dmc);
        final Function<String,Function<DataMatrix<Double>,DataMatrix<Double>>> perceptron = path -> dmx ->{
            final var aa = theta_i.apply(path);
            return dmx.perceptron(CAR(aa),CDR(aa),e->e);
        };
        
        var y = perceptron.apply("layer0/n1").apply(dd);// 标准值
        var theta_hat = theta_i.apply("layer0/n2");
        var ita = 1e-2;// learning rate
        int size = y.height();
        
        final var eps = 1e-1;// 统计误差
        var loss = Double.MAX_VALUE;
        do{
            var y_hat = perceptron.apply("layer0/n2").apply(dd);
            var delta = y_hat.sub(y);// 提取差异
            loss = delta.mul(delta).mapColumn(0, col->col.mean());
            println(loss);
            if(loss<eps)break;
            for(int i=0;i<theta_hat.length;i++) {
                double grad = 0;
                if(i>0){
                    grad = delta.mul(dd.dbl(i-1)).mapColumn(0, col->col.mean());
                }else {
                    grad = delta.mapColumn(0,col->col.mean());
                }//if
                theta_hat[i]-=grad*ita/size;
            }//for
        }while(true);
        
        println(A2REC(theta_hat).toString2(frt(2)));
    }
    
    @Test
    public void bar3() {
        var aa = CONS(2, CONS(1,null));
        println(L(aa));
        aa = REV(aa);
        println(L(aa));
        println(CAR(aa));
    }
    
}
